package sep.einfuehrung;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

/**
 * JPanel which displays an image and another image in a rectangle
 */
public class VideoPanel extends JPanel implements MouseListener,
		MouseMotionListener, ComponentListener {

	private static final long serialVersionUID = 1L;

	private volatile BufferedImage mCannyImage;
	private volatile BufferedImage mOriginalImage;
	private volatile BufferedImage mResizedOriginal;
	private Rectangle mRect = null;
	private Point mPointOrigin = null;

	/**
	 * Creates the panel
	 */
	public VideoPanel() {
		super();

		addMouseListener(this);
		addMouseMotionListener(this);
		addComponentListener(this);
	}

	/**
	 * Set the images to be drawn in this panel
	 * 
	 * @param canny
	 *            The canny edge filtered image
	 * @param original
	 *            The original unfiltered image
	 */
	public void setImages(BufferedImage canny, BufferedImage original) {
		mCannyImage = canny;
		mOriginalImage = original;
		createResizedOriginal();
		repaint();
	}

	/**
	 * Reset the display to show nothing but the rectangle
	 */
	public void reset() {
		mCannyImage = null;
		mOriginalImage = null;
		mResizedOriginal = null;
		repaint();
	}

	/**
	 * Draws the previously set canny edge filtered image (if set), the spanned
	 * rectangle (if set) and the part of the original image, which lies in the
	 * rectangle
	 */
	@Override
	protected void paintComponent(Graphics g) {
		if (mCannyImage != null) {
			// Draw the filtered image
			g.drawImage(mCannyImage, 0, 0, getWidth(), getHeight(), null);
		} else {
			// Draw the background
			super.paintComponent(g);
		}

		if (mRect != null) {
			// Draw the rectangle
			g.setColor(Color.red);
			g.drawRect(mRect.x, mRect.y, mRect.width, mRect.height);

			if (mResizedOriginal != null) {
				// Draw the unfiltered image in the rectangle
				int x1 = mRect.x + 1;
				int y1 = mRect.y + 1;
				int x2 = mRect.x + mRect.width - 1;
				int y2 = mRect.y + mRect.height - 1;
				g.drawImage(mResizedOriginal, x1, y1, x2, y2, x1, y1, x2, y2,
						null);
			}
		}
	}

	@Override
	public void mouseClicked(MouseEvent e) {
	}

	@Override
	public void mouseEntered(MouseEvent e) {
	}

	@Override
	public void mouseExited(MouseEvent e) {
	}

	/**
	 * Sets the origin of the rectangle
	 */
	@Override
	public void mousePressed(MouseEvent e) {
		if (e.getButton() == MouseEvent.BUTTON1) {
			mPointOrigin = e.getPoint();
			mRect = null;
		}
	}

	/**
	 * Sets the final rectangle and redraws
	 */
	@Override
	public void mouseReleased(MouseEvent e) {
		if (e.getButton() == MouseEvent.BUTTON1) {
			mPointOrigin = null;
			repaint();
		}
	}

	/**
	 * Updates the rectangle to the new size and redraws
	 */
	@Override
	public void mouseDragged(MouseEvent e) {
		if (mPointOrigin != null) {

			Point mousePos = e.getPoint();

			// Restrict rectangle to the inside of this component
			if (mousePos.x < 0)
				mousePos.x = 0;
			else if (mousePos.x >= getWidth())
				mousePos.x = getWidth() - 1;
			if (mousePos.y < 0)
				mousePos.y = 0;
			else if (mousePos.y >= getHeight())
				mousePos.y = getHeight() - 1;

			int width = 0;
			int height = 0;
			int x = 0;
			int y = 0;

			// Calc x and width
			if (mousePos.x < mPointOrigin.x) {
				x = mousePos.x;
				width = mPointOrigin.x - mousePos.x;
			} else {
				x = mPointOrigin.x;
				width = mousePos.x - mPointOrigin.x;
			}

			// Calc y and height
			if (mousePos.y < mPointOrigin.y) {
				y = mousePos.y;
				height = mPointOrigin.y - mousePos.y;
			} else {
				y = mPointOrigin.y;
				height = mousePos.y - mPointOrigin.y;
			}

			// Set the new size of the rectangle
			if (mRect == null)
				mRect = new Rectangle();

			mRect.setBounds(x, y, width, height);

			// Paint rectangle
			repaint();
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {
	}

	private void createResizedOriginal() {
		if (mOriginalImage != null) {
			mResizedOriginal = new BufferedImage(getWidth(), getHeight(),
					mOriginalImage.getType());
			Graphics2D g = mResizedOriginal.createGraphics();
			g.drawImage(mOriginalImage, 0, 0, getWidth(), getHeight(), null);
			g.dispose();
		}
	}

	@Override
	public void componentHidden(ComponentEvent e) {
	}

	@Override
	public void componentMoved(ComponentEvent e) {
	}

	/**
	 * Recreates the resized original image and redraws the rectangle
	 */
	@Override
	public void componentResized(ComponentEvent e) {
		createResizedOriginal();

		if (mRect != null) {
			boolean fullRedraw = false;

			// Reduce the rectangle, if its too big
			if (mRect.x + mRect.width >= getWidth()) {
				mRect.width = getWidth() - mRect.x - 1;
				fullRedraw = true;

				if (mRect.width < 0)
					mRect = null;
			}
			if (mRect != null && mRect.y + mRect.height >= getHeight()) {
				mRect.height = getHeight() - mRect.y - 1;
				fullRedraw = true;

				if (mRect.height < 0)
					mRect = null;
			}

			if (!fullRedraw)
				repaint(mRect);
			else
				repaint();
		}
	}

	@Override
	public void componentShown(ComponentEvent e) {
	}

}
